﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace BaseFramework.Test
{
    public class Win32
    {
        public const uint SHGFI_ICON = 0x100;
        public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
        public const uint SHGFI_SMALLICON = 0x1; // 'Small icon


        [DllImport("user32.dll", EntryPoint = "IsWindow")]
        public static extern bool IsWindow(IntPtr hWnd);

        [DllImport("kernel32.dll", EntryPoint = "SetLastError")]
        public static extern void SetLastError(uint dwErrCode);

        [DllImport("shell32.dll")]
        public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
        [DllImport("shell32.dll")]
        public static extern uint ExtractIconEx(string lpszFile, int nIconIndex, IntPtr[] phiconLarge, IntPtr[] phiconSmall, uint nIcons);
        [DllImport("shell32.dll", EntryPoint = "ExtractIconExW", CallingConvention = CallingConvention.StdCall)]
        public static extern uint ExtractIconExW([InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)] string lpszFile, int nIconIndex, ref System.IntPtr phiconLarge, ref System.IntPtr phiconSmall, uint nIcons);

        /// <summary>
        /// 更改窗口位置和尺寸。
        /// </summary>
        /// <param name="hWnd">窗口句柄</param>
        /// <param name="x">左侧的新位置</param>
        /// <param name="y">顶部的新位置</param>
        /// <param name="nWidth">新的宽度</param>
        /// <param name="nHeight">新的高度</param>
        /// <param name="bRepaint">是否将重新绘制。 如果 TRUE，CWnd 照常接收到其 OnPaint 消息处理程序中 WM_PAINT 消息。 如果此参数是 FALSE，重新绘制任何类型不会发生</param>
        [DllImport("user32.dll")]
        public static extern void MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool bRepaint = true);

        /// <summary>
        /// 获取窗口的边界矩形的尺寸。屏幕坐标中的尺寸与屏幕的左上角相对应。
        /// </summary>
        /// <param name="hWnd">窗口句柄</param>
        /// <param name="lpRect">将接收左上角和右下角的屏幕坐标的 Rect 结构。</param>
        [DllImport("user32.dll")]
        public static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect);

        #region GetWindowThreadProcessId
        private static System.Collections.Hashtable processWnd = new System.Collections.Hashtable();

        public delegate bool WNDENUMPROC(IntPtr hwnd, uint lParam);

        [DllImport("user32.dll", EntryPoint = "EnumWindows", SetLastError = true)]
        public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, uint lParam);

        [DllImport("user32.dll", EntryPoint = "GetParent", SetLastError = true)]
        public static extern IntPtr GetParent(IntPtr hWnd);

        [DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId")]
        public static extern uint GetWindowThreadProcessId(IntPtr hWnd, ref uint lpdwProcessId);

        /// <summary>
        /// 获取当前窗口句柄
        /// </summary>
        /// <returns></returns>
        public static IntPtr GetCurrentWindowHandle()
        {
            IntPtr ptrWnd = IntPtr.Zero;
            uint uiPid = (uint)System.Diagnostics.Process.GetCurrentProcess().Id;  // 当前进程 ID
            object objWnd = processWnd[uiPid];

            if (objWnd != null)
            {
                ptrWnd = (IntPtr)objWnd;
                if (ptrWnd != IntPtr.Zero && IsWindow(ptrWnd))  // 从缓存中获取句柄
                {
                    return ptrWnd;
                }
                else
                {
                    ptrWnd = IntPtr.Zero;
                }
            }

            bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), uiPid);
            // 枚举窗口返回 false 并且没有错误号时表明获取成功
            if (!bResult && Marshal.GetLastWin32Error() == 0)
            {
                objWnd = processWnd[uiPid];
                if (objWnd != null)
                {
                    ptrWnd = (IntPtr)objWnd;
                }
            }

            return ptrWnd;
        }

        private static bool EnumWindowsProc(IntPtr hwnd, uint lParam)
        {
            uint uiPid = 0;

            if (GetParent(hwnd) == IntPtr.Zero)
            {
                GetWindowThreadProcessId(hwnd, ref uiPid);
                if (uiPid == lParam)    // 找到进程对应的主窗口句柄
                {
                    processWnd[uiPid] = hwnd;   // 把句柄缓存起来
                    SetLastError(0);    // 设置无错误
                    return false;   // 返回 false 以终止枚举窗口
                }
            }

            return true;
        }

        #endregion

        #region  SetConsoleCtrlHandler
        /// <summary>
        /// 添加或删除应用程序处理函数列表
        /// </summary>
        /// <param name="HandlerRoutine">回调函数</param>
        /// <param name="Add">表示添加还是删除</param>
        /// <returns>如果函数成功，返回值为false.否则，返回一个非0值</returns>
        [DllImport("kernel32.dll")]
        public static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
        /// <summary>
        /// 定义处理程序委托
        /// </summary>
        /// <param name="ctrlType"></param>
        /// <returns></returns>
        public delegate bool ConsoleCtrlDelegate(int ctrlType);
        /// <summary>
        /// Ctrl+C，系统会发送次消息
        /// </summary>
        public const int CTRL_C_EVENT = 0;
        /// <summary>
        /// Ctrl+break，系统会发送次消息
        /// </summary>
        public const int CTRL_BREAK_EVENT = 1;
        /// <summary>
        /// 当用户关闭Console时，系统会发送次消息
        /// </summary>
        public const int CTRL_CLOSE_EVENT = 2;
        /// <summary>
        /// 用户退出（注销），系统会发送次消息
        /// </summary>
        public const int CTRL_LOGOFF_EVENT = 5;
        /// <summary>
        /// 系统关闭，系统会发送次消息
        /// </summary>
        public const int CTRL_SHUTDOWN_EVENT = 6;
        #endregion
    }
    public enum SystemIcon
    {
        Default = 0,
        Exe = 2,
        Folder = 4,
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SHFILEINFO
    {
        public IntPtr hIcon;
        public IntPtr iIcon;
        public uint dwAttributes;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string szDisplayName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
        public string szTypeName;
    }

    /// <summary>
    /// 定义矩形左上角和右下角的坐标。
    /// </summary>
    public struct Rect
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }
}
